package com.gopay.solution.manager.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.gopay.common.cache.client.RedisClient;
import com.gopay.common.cache.constants.RedisConstants;
import com.gopay.common.constants.Constants;
import com.gopay.common.constants.solution.SolutionTypeConstant;
import com.gopay.common.util.FastJsonUtil;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.gopay.common.util.DateUtils;
import com.gopay.solution.dao.SolutionMetaDAO;
import com.gopay.solution.dao.SolutionRuleDtlDAO;
import com.gopay.solution.domain.po.SolutionMeta;
import com.gopay.solution.domain.po.SolutionRuleDtl;
import com.gopay.solution.domain.vo.Solution;
import com.gopay.solution.manager.SolutionManager;

/**
 * 方案管理器模版 本模版不可继承，用于SPRING方式配置每个具体方案的配置BEAN
 * 
 * @SolutionManagerTemplate.java
 * @author MA HUAN
 * @2013-3-26 上午11:41:08 www.gopay.com.cn Inc.All rights reserved.
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public final class SolutionManagerTemplate implements SolutionManager {

    private  final Logger logger = LoggerFactory.getLogger(getClass());

    private SolutionMetaDAO solutionMetaDAO;

    private SolutionRuleDtlDAO solutionRuleDtlDAO;

    @Autowired
    RedisConstants redisConstants;

    public SolutionMetaDAO getSolutionMetaDAO() {
        return solutionMetaDAO;
    }

    public void setSolutionMetaDAO(SolutionMetaDAO solutionMetaDAO) {
        this.solutionMetaDAO = solutionMetaDAO;
    }

    public SolutionRuleDtlDAO getSolutionRuleDtlDAO() {
        return solutionRuleDtlDAO;
    }

    public void setSolutionRuleDtlDAO(SolutionRuleDtlDAO solutionRuleDtlDAO) {
        this.solutionRuleDtlDAO = solutionRuleDtlDAO;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public Solution upgrade(long seq) {
        
        SolutionMeta meta = solutionMetaDAO.getByPk(seq);
        if(meta != null) {
            
            Date current = DateUtils.getSystemDate();
            //在源方案数据基础上升级版本，并保存新版本元数据
            meta.setSolutionVersion(meta.getSolutionVersion() + 1);
            meta.setSolutionId(nextSolutionId());
            meta.setCreateTime(current);
            meta.setLastUpdTime(current);
            solutionMetaDAO.save(meta);
            
            List<SolutionRuleDtl> dtls = solutionRuleDtlDAO.listBySolutionId(seq);
            if(dtls != null) {
                for(SolutionRuleDtl dtl : dtls) {
                    dtl.setSq(nextSolutionDtlId());
                    dtl.setSolutionId(meta.getSolutionId());
                    dtl.setCreateTime(current);
                    dtl.setLastUpdTime(current);
                    
                    solutionRuleDtlDAO.save(dtl);
                }
            }
            
            Solution solu = new Solution();
            solu.setMeta(meta);
            solu.setRuleDtls(dtls);
            
            return solu;
        }
        
        return null;
    }
    
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public Solution clone(long seq) {
        SolutionMeta meta = solutionMetaDAO.getByPk(seq);
        if(meta != null) {
            
            Date current = DateUtils.getSystemDate();
            //在源方案数据基础上克隆版本，并保存新版本元数据
            meta.setSolutionCode(meta.getSolutionCode() + 1);
            meta.setSolutionVersion(1L);
            meta.setSolutionId(nextSolutionId());
            meta.setCreateTime(current);
            meta.setLastUpdTime(current);
            solutionMetaDAO.save(meta);
            
            List<SolutionRuleDtl> dtls = solutionRuleDtlDAO.listBySolutionId(seq);
            if(dtls != null) {
                for(SolutionRuleDtl dtl : dtls) {
                    dtl.setSq(nextSolutionDtlId());
                    dtl.setSolutionId(meta.getSolutionId());
                    dtl.setCreateTime(current);
                    dtl.setLastUpdTime(current);
                    
                    solutionRuleDtlDAO.save(dtl);
                }
            }
            
            Solution solu = new Solution();
            solu.setMeta(meta);
            solu.setRuleDtls(dtls);
            
            return solu;
        }
        
        return null;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public boolean modify(Solution solution) {
        
        if(solution == null || solution.getMeta() == null || solution.getRuleDtls() == null || solution.getRuleDtls().isEmpty()) {
            return false;
        }
        //更新元数据信息
        solutionMetaDAO.update(solution.getMeta());
        //删除老旧明细信息
        solutionRuleDtlDAO.delBySolutionId(solution.getMeta().getSolutionId());
        //保存新的明细信息
        List<SolutionRuleDtl> dtls = solution.getRuleDtls();
        for (SolutionRuleDtl dtl : dtls) {
            solutionRuleDtlDAO.save(dtl);// BaseDAO貌似不支持批量插入
        }
        
        return true;
    }
    
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public boolean modifyBySeqAndIntTxnCd(Solution solution, String intTxnCd) {
        if(solution.getMeta() == null || solution.getRuleDtls() == null || StringUtils.isEmpty(intTxnCd)) {
            return false;
        }
        //更新元数据信息
        solutionMetaDAO.update(solution.getMeta());
        //删除老旧明细信息
        solutionRuleDtlDAO.delBySoluIdAndIntTxnCd(solution.getMeta().getSolutionId(), intTxnCd);
        //保存新的明细信息
        List<SolutionRuleDtl> dtls = solution.getRuleDtls();
        for (SolutionRuleDtl dtl : dtls) {
            solutionRuleDtlDAO.save(dtl);// BaseDAO貌似不支持批量插入
        }
        
        return true;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public boolean modifyBySeqAndIntTxnCd(Solution solution, String intTxnCd ,String solutionType,String prodCode) {
        String key = FastJsonUtil.getKey(redisConstants.getRedisEnvironment(),Constants.CACHE_CHANNEL_SOLUTION, prodCode,intTxnCd ,solutionType);
        //账户类型不为空的时候清理缓存
        if (StringUtils.isNotEmpty(prodCode)){
            Long del = RedisClient.del(key);
            if (del!=null){
                if (1==del){
                    logger.info("======>第一次清理缓存成功，key为 {}",key);
                }else{
                    logger.info("======>第一次缓存不存在，未清理，key为 {}",key);
                }
            }
        }else{
            logger.info("======>账户类型不存在，未处理，key为 {}",key);
        }
        boolean ret;
        try {
            ret = modifyBySeqAndIntTxnCd(solution,intTxnCd);
        } finally {
            if (StringUtils.isNotEmpty(prodCode)){
                Long del = RedisClient.del(key);
                if (del!=null){
                    if (1==del){
                        logger.info("======>第二次清理缓存成功，key为 {}",key);
                    }else{
                        logger.info("======>第二次缓存不存在，未清理，key为 {}",key);
                    }
                }
            }
        }
        return ret;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public boolean save(Solution solution) {
        if(null == solution){
            return false;
        }
        SolutionMeta meta = solution.getMeta();
        List<SolutionRuleDtl> dtls = solution.getRuleDtls();
        
        //元数据和明细不能为空
        if(meta == null || dtls == null || dtls.isEmpty()) {
            return false;
        }
        
        solutionMetaDAO.save(meta);
        
        for (SolutionRuleDtl dtl : dtls) {
            solutionRuleDtlDAO.save(dtl);// BaseDAO貌似不支持批量插入
        }
        return true;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public boolean delete(long seq) {

        SolutionMeta meta = solutionMetaDAO.getByPk(seq);
        if (meta != null) {
            // 删除元数据
            solutionMetaDAO.delete(meta);
            // 删除明细数据
            solutionRuleDtlDAO.delBySolutionId(seq);
        }
        return true;
    }

    @Override
    public Solution load(long seq) {

        SolutionMeta meta = solutionMetaDAO.getByPk(seq);
        if (meta != null) {
            List<SolutionRuleDtl> dtls = solutionRuleDtlDAO.listBySolutionId(meta.getSolutionId());
            if (dtls != null && dtls.size() > 0) {

                Solution solu = new Solution();
                solu.setMeta(meta);
                solu.setRuleDtls(dtls);

                return solu;
            }
        }

        return null;
    }
    
    @Override
    public Solution loadBySeqAndIntTxnCd(long seq, String intTxnCd) {
        SolutionMeta meta = solutionMetaDAO.getByPk(seq);
        if (meta != null) {
            Solution solu = new Solution();
            solu.setMeta(meta);
            
            List<SolutionRuleDtl> dtls = solutionRuleDtlDAO.listBySoluIdAndIntTxnCd(meta.getSolutionId(), intTxnCd);
            if (dtls != null && dtls.size() > 0) {
                solu.setRuleDtls(dtls);
            }
            
            return solu;
        }

        return null;
    }

    @Override
    public List<Solution> loadAll() {
        List<SolutionMeta> metas = solutionMetaDAO.getAll();
        if (metas != null && metas.size() > 0) {
            List<Solution> res = new ArrayList<Solution>();

            for (SolutionMeta meta : metas) {

                List<SolutionRuleDtl> dtls = solutionRuleDtlDAO.listBySolutionId(meta.getSolutionId());

                Solution solu = new Solution();
                solu.setMeta(meta);
                solu.setRuleDtls(dtls);

                res.add(solu);
            }

            return res;
        }
        return null;
    }

    @Override
    public long nextSolutionId() {
        return System.currentTimeMillis();
    }
    
    @Override
    public long nextSolutionDtlId() {
        return System.currentTimeMillis() + RandomUtils.nextInt();
    }
    
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public boolean delBySoluIdAndIntTxnCd(Long solutionId,String intTxnCd){
        return solutionRuleDtlDAO.delBySoluIdAndIntTxnCd(solutionId, intTxnCd);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public boolean delBySoluIdAndIntTxnCd(Long solutionId,String intTxnCd,String solutionType,String prodCode){
        RedisClient.del(FastJsonUtil.getKey(redisConstants.getRedisEnvironment(),Constants.CACHE_CHANNEL_SOLUTION,prodCode,intTxnCd,solutionType));
        boolean ret;
        try {
            ret = delBySoluIdAndIntTxnCd(solutionId, intTxnCd);
        } finally {
            RedisClient.del(FastJsonUtil.getKey(redisConstants.getRedisEnvironment(),Constants.CACHE_CHANNEL_SOLUTION,prodCode,intTxnCd,solutionType));
        }
        return ret;
    }
}
